---
title: Complex Writing
description: Implement batch writing, data updating, and other operations through complex writing operations.
---

## Overview
The complex writing feature supports various Excel data export requirements by supporting features such as specifying column order, dynamic column headers, merging cells, and custom styles.

## **Export Only Specified Columns Based on Parameters**

### Overview
Dynamically select columns to export by setting a collection of column names, supporting ignoring columns or exporting only specific columns.

### excel 示例
![img](/images/docs/write_hard/excludeOrIncludeWrite.png)

#### Code Example
```java
@Test
public void excludeOrIncludeWrite() {
    String fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";

    // Exclude specified columns
    Set<String> excludeColumns = Set.of("date");
    FastExcel.write(fileName, DemoData.class)
        .excludeColumnFiledNames(excludeColumns)
        .sheet("Template")
        .doWrite(data());

    // Export only specified columns
    Set<String> includeColumns = Set.of("date");
    FastExcel.write(fileName, DemoData.class)
        .includeColumnFiledNames(includeColumns)
        .sheet("Template")
        .doWrite(data());
}
```



## **Specify the Order of Columns to Write**

### Overview
Specify the column order using the `@ExcelProperty` annotation's `index` attribute.

### excel 示例
![img](/images/docs/write_hard/indexWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
public class IndexData {
    @ExcelProperty(value = "String Title", index = 0)
    private String string;
    @ExcelProperty(value = "Date Title", index = 1)
    private Date date;
    @ExcelProperty(value = "Number Title", index = 3)
    private Double doubleData; // Leave the second column empty
}
```

#### Code Example
```java
@Test
public void indexWrite() {
    String fileName = "indexWrite" + System.currentTimeMillis() + ".xlsx";
    FastExcel.write(fileName, IndexData.class)
        .sheet("Template")
        .doWrite(data());
}
```


## **Complex Header Writing**

### Overview
Supports setting multi-level headers by specifying main titles and sub-titles using the `@ExcelProperty` annotation.

### excel 示例
![img](/images/docs/write_hard/complexHeadWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
public class ComplexHeadData {
    @ExcelProperty({"Main Title", "String Title"})
    private String string;
    @ExcelProperty({"Main Title", "Date Title"})
    private Date date;
    @ExcelProperty({"Main Title", "Number Title"})
    private Double doubleData;
}
```

#### Code Example
```java
@Test
public void complexHeadWrite() {
    String fileName = "complexHeadWrite" + System.currentTimeMillis() + ".xlsx";
    FastExcel.write(fileName, ComplexHeadData.class)
        .sheet("Template")
        .doWrite(data());
}
```



## **Batch Writing Multiple Times**

### Overview
Write data to the same sheet or multiple sheets in batches to achieve pagination writing for large amounts of data.

### excel 示例
![img](/images/docs/write_hard/repeatedWrite.png)

#### Code Example
```java
@Test
public void repeatedWrite() {
    String fileName = "repeatedWrite" + System.currentTimeMillis() + ".xlsx";

    // Method 1: Write to the same sheet
    try (ExcelWriter excelWriter = FastExcel.write(fileName, DemoData.class).build()) {
        WriteSheet writeSheet = FastExcel.writerSheet("Template").build();
        for (int i = 0; i < 5; i++) {
            excelWriter.write(data(), writeSheet);
        }
    }

    // Method 2: Write to multiple sheets
    try (ExcelWriter excelWriter = FastExcel.write(fileName, DemoData.class).build()) {
        for (int i = 0; i < 5; i++) {
            WriteSheet writeSheet = FastExcel.writerSheet(i, "Template" + i).build();
            excelWriter.write(data(), writeSheet);
        }
    }
}
```



## **Custom Format Writing**

### Overview
Supports date, number, or other custom formats through annotations.

### excel 示例
![img](/images/docs/write_hard/converterWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
public class ConverterData {
    @ExcelProperty(value = "String Title", converter = CustomStringStringConverter.class)
    private String string;

    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty("Date Title")
    private Date date;

    @NumberFormat("#.##%")
    @ExcelProperty("Number Title")
    private Double doubleData;
}
```

#### Code Example
```java
@Test
public void converterWrite() {
    String fileName = "converterWrite" + System.currentTimeMillis() + ".xlsx";
    FastExcel.write(fileName, ConverterData.class)
        .sheet("Template")
        .doWrite(data());
}
```



## **Custom Styles**

### Annotation Form

#### Overview
Set cell styles in the entity class using annotations, including font, background color, row height, etc.

### excel 示例
![img](/images/docs/write_hard/annotationStyleWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
// Set header background color to red
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 10)
// Set header font size to 20
@HeadFontStyle(fontHeightInPoints = 20)
// Set content background color to green
@ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 17)
// Set content font size to 20
@ContentFontStyle(fontHeightInPoints = 20)
public class DemoStyleData {
    // Set header and content styles for a specific column
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 14)
    @HeadFontStyle(fontHeightInPoints = 30)
    @ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    @ContentFontStyle(fontHeightInPoints = 30)
    @ExcelProperty("String Title")
    private String string;

    @ExcelProperty("Date Title")
    private Date date;

    @ExcelProperty("Number Title")
    private Double doubleData;
}
```

#### Sample Code
```java
@Test
public void annotationStyleWrite() {
    String fileName = "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoStyleData.class)
        .sheet("Style Template")
        .doWrite(data());
}
```



### **Interceptor Form**

#### Overview
Dynamically set styles by implementing the `WriteHandler` interceptor interface, suitable for complex style logic.

### excel 示例
![img](/images/docs/write_hard/handlerStyleWrite.png)

#### Example 1: Using Existing Strategy
Set styles for headers and content separately using `HorizontalCellStyleStrategy`.

#### Code Example
```java
@Test
public void handlerStyleWrite() {
    String fileName = "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx";

    // Define header style
    WriteCellStyle headStyle = new WriteCellStyle();
    headStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); // Red background
    WriteFont headFont = new WriteFont();
    headFont.setFontHeightInPoints((short) 20); // Font size 20
    headStyle.setWriteFont(headFont);

    // Define content style
    WriteCellStyle contentStyle = new WriteCellStyle();
    contentStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); // Green background
    contentStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    WriteFont contentFont = new WriteFont();
    contentFont.setFontHeightInPoints((short) 20);
    contentStyle.setWriteFont(contentFont);

    // Use strategy to set styles
    HorizontalCellStyleStrategy styleStrategy =
        new HorizontalCellStyleStrategy(headStyle, contentStyle);

    FastExcel.write(fileName, DemoData.class)
        .registerWriteHandler(styleStrategy)
        .sheet("Style Template")
        .doWrite(data());
}
```



#### Example 2: Fully Custom Interceptor
If existing strategies do not meet requirements, implement the `CellWriteHandler` interface to fully customize style control.

#### Custom Interceptor
```java
@Slf4j
public class CustomCellStyleWriteHandler implements CellWriteHandler {

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        // Set style only for content cells
        if (BooleanUtils.isNotTrue(context.getHead())) {
            WriteCellData<?> cellData = context.getFirstCellData();
            WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();

            // Set background color to yellow
            writeCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
            writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);

            // Set font color to blue
            WriteFont writeFont = new WriteFont();
            writeFont.setColor(IndexedColors.BLUE.getIndex());
            writeFont.setFontHeightInPoints((short) 14); // Font size 14
            writeCellStyle.setWriteFont(writeFont);

            log.info("Custom cell style set: Row {}, Column {}", context.getRowIndex(), context.getColumnIndex());
        }
    }
}
```

#### Sample Code
```java
@Test
public void customCellStyleWrite() {
    String fileName = "customCellStyleWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoData.class)
        .registerWriteHandler(new CustomCellStyleWriteHandler())
        .sheet("Custom Style")
        .doWrite(data());
}
```



#### Example 3: Customizing Styles Using `POI`
Directly manipulate the POI `CellStyle` for precise style control.

#### Sample Code
```java
@Test
public void poiStyleWrite() {
    String fileName = "poiStyleWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoData.class)
        .registerWriteHandler(new CellWriteHandler() {
            @Override
            public void afterCellDispose(CellWriteHandlerContext context) {
                if (BooleanUtils.isNotTrue(context.getHead())) {
                    Cell cell = context.getCell();
                    Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();

                    // Create and set style
                    CellStyle cellStyle = workbook.createCellStyle();
                    cellStyle.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
                    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                    cell.setCellStyle(cellStyle);
                }
            }
        })
        .sheet("POI Style")
        .doWrite(data());
}
```



### **Application Scenarios**

| Scenario                        | Suggested Method           | Example          |
|---------------------------------|----------------------------|------------------|
| Simple Style Setting            | Annotation Form             | Example 1        |
| Dynamic Style Setting for Different Columns or Rows | Using Existing Strategy | Example 2-1      |
| Complex Condition Control for Styles | Custom Interceptor          | Example 2-2      |
| Precise Control of Cell Styles  | POI Customization           | Example 3        |




## **Image Export**

### Overview
Supports exporting images using files, streams, byte arrays, URLs, and other methods.

### excel 示例
![img](/images/docs/write_hard/imgWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
@ContentRowHeight(100)
@ColumnWidth(25)
public class ImageDemoData {
    private File file;
    private InputStream inputStream;
    @ExcelProperty(converter = StringImageConverter.class)
    private String string;
    private byte[] byteArray;
    private URL url;
}
```

#### Code Example
```java
@Test
public void imageWrite() throws Exception {
    String fileName = "imageWrite" + System.currentTimeMillis() + ".xlsx";
    String imagePath = "path/to/image.jpg";

    List<ImageDemoData> list = new ArrayList<>();
    ImageDemoData data = new ImageDemoData();
    data.setFile(new File(imagePath));
    data.setByteArray(Files.readAllBytes(Paths.get(imagePath)));
    data.setUrl(new URL("https://example.com/image.jpg"));
    list.add(data);

    FastExcel.write(fileName, ImageDemoData.class)
        .sheet()
        .doWrite(list);
}
```



## **Hyperlinks, Comments, Formulas Writing**

### Overview
Supports cell hyperlinks, adding comments, and setting formula content.

### excel 示例
![img](/images/docs/write_hard/writeCellDataWrite.png)

#### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
public class WriteCellDemoData {
    private WriteCellData<String> hyperlink;
    private WriteCellData<String> commentData;
    private WriteCellData<String> formulaData;
}
```

#### Code Example
```java
@Test
public void writeCellDataWrite() {
    String fileName = "writeCellDataWrite" + System.currentTimeMillis() + ".xlsx";
    WriteCellDemoData data = new WriteCellDemoData();

    // Set hyperlink
    data.setHyperlink(new WriteCellData<>("Click to Visit").hyperlink("https://example.com"));

    // Set comment
    data.setCommentData(new WriteCellData<>("Comment Information"));

    // Set formula
    data.setFormulaData(new WriteCellData<>("=SUM(A1:A10)"));

    FastExcel.write(fileName, WriteCellDemoData.class)
        .sheet("Template")
        .doWrite(Collections.singletonList(data));
}
```



## **Dynamic Header Writing**

### Overview
Generate table headers dynamically for dynamic data or internationalization scenarios.

### excel 示例
![img](/images/docs/write_hard/dynamicHeadWrite.png)

#### Code Example
```java
@Test
public void dynamicHeadWrite() {
    String fileName = "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";

    List<List<String>> head = Arrays.asList(
        Collections.singletonList("Dynamic String Title"),
        Collections.singletonList("Dynamic Number Title"),
        Collections.singletonList("Dynamic Date Title")
    );

    FastExcel.write(fileName).head(head)
        .sheet("Template")
        .doWrite(data());
}
```


## **Inserting Comments**

### Overview
Add comments to specific cells using interceptors, suitable for marking explanations or special tips.

### excel 示例
![img](/images/docs/write_hard/commentWrite.png)

### Custom Comment Interceptor
```java
@Slf4j
public class CommentWriteHandler implements RowWriteHandler {

    @Override
    public void afterRowDispose(RowWriteHandlerContext context) {
        if (BooleanUtils.isTrue(context.getHead())) {
            Sheet sheet = context.getWriteSheetHolder().getSheet();
            Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
            // Create a comment at row 1, column 2
            Comment comment = drawingPatriarch.createCellComment(
                new XSSFClientAnchor(0, 0, 0, 0, (short) 1, 0, (short) 2, 1));
            comment.setString(new XSSFRichTextString("Comment Content"));
            sheet.getRow(0).getCell(1).setCellComment(comment);
        }
    }
}
```

### Sample Code
```java
@Test
public void commentWrite() {
    String fileName = "commentWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoData.class)
        .inMemory(Boolean.TRUE) // Comments must be enabled in memory mode
        .registerWriteHandler(new CommentWriteHandler())
        .sheet("Comment Example")
        .doWrite(data());
}
```



## **Write Based on Template**

### Overview
Supports filling data on an existing template file, suitable for standardized output.

### excel 示例
![img](/images/docs/write_hard/commentWrite.png)

### Sample Code
```java
@Test
public void templateWrite() {
    String templateFileName = "path/to/template.xlsx";
    String fileName = "templateWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoData.class)
        .withTemplate(templateFileName)
        .sheet()
        .doWrite(data());
}
```



## **Column Width, Row Height**

### Overview
Control column width and row height through annotations, suitable for scenarios with specific table format requirements.

### excel 示例
![img](/images/docs/write_hard/widthAndHeightWrite.png)

### Sample Object
```java
@Getter
@Setter
@EqualsAndHashCode
@ContentRowHeight(20)
@HeadRowHeight(30)
@ColumnWidth(25) // Default column width
public class WidthAndHeightData {
    @ExcelProperty("String Title")
    private String string;

    @ExcelProperty("Date Title")
    private Date date;

    @ColumnWidth(50) // Set column width individually
    @ExcelProperty("Number Title")
    private Double doubleData;
}
```

### Sample Code
```java
@Test
public void widthAndHeightWrite() {
    String fileName = "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, WidthAndHeightData.class)
        .sheet("Width and Height Example")
        .doWrite(data());
}
```



## **Merge Cells**

### Overview
Supports merging cells using annotations or custom merge strategies.

### excel 示例
![img](/images/docs/write_hard/mergeWrite.png)

### Method 1: Annotation Form
```java
@Getter
@Setter
@EqualsAndHashCode
public class DemoMergeData {
    @ContentLoopMerge(eachRow = 2) // Merge every 2 rows
    @ExcelProperty("String Title")
    private String string;

    @ExcelProperty("Date Title")
    private Date date;

    @ExcelProperty("Number Title")
    private Double doubleData;
}
```

### Method 2: Custom Merge Strategy
```java
public class CustomMergeStrategy extends AbstractMergeStrategy {
    @Override
    protected void merge(Sheet sheet, WriteSheetHolder writeSheetHolder) {
        // Custom merge rules
        sheet.addMergedRegion(new CellRangeAddress(1, 2, 0, 1)); // Sample merge range
    }
}
```

### Sample Code
```java
@Test
public void mergeWrite() {
    String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";

    // Annotation method
    FastExcel.write(fileName, DemoMergeData.class)
        .sheet("Merge Example")
        .doWrite(data());

    // Custom merge strategy
    FastExcel.write(fileName, DemoData.class)
        .registerWriteHandler(new CustomMergeStrategy())
        .sheet("Custom Merge")
        .doWrite(data());
}
```



## **Write Using Table**

### Overview
Supports writing multiple tables in one sheet.

### excel 示例
![img](/images/docs/write_hard/tableWrite.png)

### Sample Code
```java
@Test
public void tableWrite() {
    String fileName = "tableWrite" + System.currentTimeMillis() + ".xlsx";

    try (ExcelWriter excelWriter = FastExcel.write(fileName, DemoData.class).build()) {
        WriteSheet writeSheet = FastExcel.writerSheet("Table Example").build();
        WriteTable table1 = FastExcel.writerTable(0).build();
        WriteTable table2 = FastExcel.writerTable(1).build();

        excelWriter.write(data(), writeSheet, table1);
        excelWriter.write(data(), writeSheet, table2);
    }
}
```



## **Dynamic Header Writing**

### Overview
Generate dynamic table headers for scenarios where the header content changes dynamically.

### excel 示例
![img](/images/docs/write_hard/dynamicHeadWrite.png)

### Sample Code
```java
@Test
public void dynamicHeadWrite() {
    String fileName = "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";

    List<List<String>> head = Arrays.asList(
        Collections.singletonList("Dynamic String Title"),
        Collections.singletonList("Dynamic Number Title"),
        Collections.singletonList("Dynamic Date Title"));

    FastExcel.write(fileName)
        .head(head)
        .sheet("Dynamic Header")
        .doWrite(data());
}
```



## **Custom Interceptors**

### Overview
Custom logic implementation (such as adding dropdowns, setting hyperlinks) requires operation through interceptors.

### excel 示例
![img](/images/docs/write_hard/customHandlerWrite.png)

### Example 1: Setting Dropdowns
```java
public class DropdownWriteHandler implements SheetWriteHandler {
    @Override
    public void afterSheetCreate(SheetWriteHandlerContext context) {
        DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();
        CellRangeAddressList range = new CellRangeAddressList(1, 10, 0, 0); // Dropdown area
        DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"Option 1", "Option 2"});
        DataValidation validation = helper.createValidation(constraint, range);
        context.getWriteSheetHolder().getSheet().addValidationData(validation);
    }
}
```

### Sample Code
```java
@Test
public void customHandlerWrite() {
    String fileName = "customHandlerWrite" + System.currentTimeMillis() + ".xlsx";

    FastExcel.write(fileName, DemoData.class)
        .registerWriteHandler(new DropdownWriteHandler())
        .sheet("Custom Interceptors")
        .doWrite(data());
}
```